﻿using PLC.Base;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace PLC.Device
{
    class SerialPortManager : IDeviceReader
    {
        #region 私有变量区
        bool isOpen = false;


        SerialPort serialPort = null;
        String port = "COM6";
        int baudRate = 9600;
        Parity parity = Parity.None;
        StopBits stopBits = StopBits.One;
        int dataBits = 8;
        double transformationRatio = 1.0f;

        Semaphore sema = new Semaphore(0, 1);


        #endregion

        #region 构造函数
        public SerialPortManager(String port, int baudRate, Parity parity, int dataBits, StopBits stopBits)
        {
            this.port = port;
            this.baudRate = baudRate;
            this.parity = parity;
            this.dataBits = dataBits;
            this.stopBits = stopBits;
            if (serialPort == null)
            {
                serialPort = new SerialPort(port, baudRate, parity, dataBits, stopBits);
            }
        }
        #endregion

        #region IDeviceReader接口实现
        public bool IsOpen { get => isOpen; set => isOpen = value; }

        public int Open()
        {

            if (!isOpen)
            {
                /*
                serialPort.ReceivedBytesThreshold = 1;
                serialPort.DtrEnable = true;//获取或设置一个值，该值在串行通信过程中启用数据终端就绪 (DTR) 信号。
                serialPort.RtsEnable = true;//获取或设置一个值，该值指示在串行通信中是否启用请求发送 (RTS) 信号
                                            //设置数据读取超时为1秒
    */            
                serialPort.ReadTimeout = 1000;
                serialPort.Open();
                //serialPort.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
                isOpen = true;

            }
            return 0;

        }

        public void Close()
        {
            if (isOpen)
            {
                //serialPort.DataReceived -= port_DataReceived;
                serialPort.Close();
                isOpen = false;
            }
        }

        public EnvData ReadData(DynamicParams dynamicParams )
        {
            EnvData data = new EnvData();
            byte[] byteData = readData();
            if (byteData != null)
            {
                data.Voltage = BitConverter.ToSingle(new byte[] { byteData[51], byteData[52], byteData[53], byteData[54] }, 0)*transformationRatio;
                data.Current = BitConverter.ToSingle(new byte[] { byteData[55], byteData[56], byteData[57], byteData[58] }, 0)*transformationRatio;
                data.ShaftPower = BitConverter.ToSingle(new byte[] { byteData[59], byteData[60], byteData[61], byteData[62] }, 0)*transformationRatio;
            }

            return data;
        }

        #endregion

        #region 信号量版本
        /*
        Semaphore sema = new Semaphore(0, 1);
        volatile List<byte> portContent = new List<byte>();
        public byte[] readData()
        {
            //Console.WriteLine("begin read!!!");
            if (serialPort.IsOpen)
            {
                serialPort.Write(new byte[] { 0x55,0x1,0x34,0x8A}, 0, 4);

                bool ret = sema.WaitOne(1000);
                if (!ret)
                {
                    sema.Release();
                }
                else
                {
                    if (portContent.Count != 0)
                    {
                        byte[] receivedData = new byte[portContent.Count];
                        portContent.CopyTo(receivedData);
                        portContent.Clear();
                        return receivedData;
                    }
                    

                }

                return null;
            }
            return null;

        }

        

        private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            
                try
                {
                    int buffer = serialPort.BytesToRead;
                    byte[] receivedData = new byte[buffer]; 
                    serialPort.Read(receivedData, 0, receivedData.Length);

                    StringBuilder sb = new StringBuilder();
                    //sb.Append("recieved (" + buffer + "):bytes, type:"+e.EventType+")");
                    for (int i = 0; i < receivedData.Length; i++)
                    {
                        portContent.Add(receivedData[i]);
                        //sb.Append(receivedData[i].ToString() + " ");
                    }
                    if (portContent.Count >= 24)
                    {
                        sema.Release();
                    }
                }
                catch (System.Exception ex)
                {
                    portContent.Clear();
                    sema.Release();
                }
        }
        */
        #endregion

        #region 等待版本


        /// <summary>
        /// 根据网上的说法，DataReceived回调的时候，缓冲区的数据可能没有被准备好，需要在回调函数port_DataReceived中等待一下
        /// </summary>
        /// <returns></returns>
        private byte[] readData()
        {
            byte[] portDataArr = new byte[72];
            //Console.WriteLine("begin read!!!");
            if (serialPort.IsOpen)
            {
                serialPort.Write(new byte[] { 0x55, 0x1, 0x34, 0x8A }, 0, 4);

                //采用信号量锁住了，确保只有一个任务接收
                bool ret = sema.WaitOne(1000);
                int counter = 0;
                int buffer = serialPort.BytesToRead;
                while (buffer < 72 && counter++ < 50)
                {
                    Thread.Sleep(20);
                    buffer = serialPort.BytesToRead;
                }


                if (counter >= 50 || buffer < 72)
                {
                    sema.Release();
                    return null;
                }

                serialPort.Read(portDataArr, 0, 72);

                return portDataArr;
            }

            return null;
        }





        #endregion

    }
}
